const { CRC } = require('./crc')
const { a } = require('./Led')
const { TextCodec } = require('./gbk')
const { MyUdpSocket } = require('./udpClient')

class LEDSender {

  static Region_width = 256
  static Region_height = 32

  constructor(addr = 0, time = 5000) {
    this.timer = time
    this.dstAddr = addr
    this.data_stream = new Buffer.alloc(1 << 22)
    this.depositSizeIndex = [4, 36, 68, 108, 120]
  }

  //填充1个byte的数据
  byteFill(val) {
    this.data_stream.writeUInt8(val, this.currentIndex)
    this.currentIndex += 1
  }

  //填充2个byte的数据
  shortFill(val) {
    this.data_stream.writeUInt16LE(val, this.currentIndex)
    this.currentIndex += 2
  }

  //填充4个byte的数据
  intFill(val) {
    this.data_stream.writeUInt32LE(val, this.currentIndex)
    this.currentIndex += 4
  }

  changeTypeDataSize(addSize, extraSize) {
    for (let i = 0; i < addSize; i++) {
      this.addDataSize(this.depositSizeIndex[i], extraSize)
    }
  }

  /**
   * @param {number} oldOrganizationIndex 旧组织存放size的位置
   * @param {number} extraSize 新增加组织size的大小
   * 在增加新组织后，将旧组织中的size加上新组织的size
   * */
  addDataSize(oldOrganizationIndex, extraSize) {
    let newSumSize = this.data_stream.readUInt32LE(oldOrganizationIndex) + extraSize
    this.data_stream.writeUInt32LE(newSumSize, oldOrganizationIndex)
  }

  /**
   * 节目数据头部
   * */
  makeRoot() {
    this.currentIndex = 0
    this.shortFill(0x21) //Id  2  节目代码  0x21：发送节目  0x22：下载节目
    this.shortFill(2) //Type  2  节目类型  1：单路数据  2：RG双路数据
    this.intFill(20) //Size  4  数据长度，TRoot长度+所有子数据长度
    this.intFill(1) //Count  4  章节数量
    this.intFill(0xFFFFFFFF) //Survive  4  存在时间长度（毫秒）
    this.shortFill(0) //Flag  2  标志，置0
    this.shortFill(0) //Reserved  2  保留，置0
    //console.log(this.data_stream);
  }

  /**
   * 章节
   * */
  addChapter() {
    this.shortFill(0x3F) //Id  2  章节标识代码 =0x3F
    this.shortFill(0) //No  2  置0
    this.shortFill(1) //Wait  2  是否等待播放完成 =1等待 =0到时间就切
    this.shortFill(0) //Repeat  2  置0
    this.shortFill(1) //Count  2  区域数量
    this.shortFill(0xFFFF) //Reserved  2  存在时间长度
    this.intFill(0x7FFFFFFF) //Time  4  时间长度（毫秒）
    this.intFill(40) //chapter的字节size //Size  4  数据长度，TChapter长度+所有子数据长度
    //Others  20  播放计划相关参数，全部置0
    for (let i = 0; i < 5; i++) {
      this.intFill(0)
    }
    this.changeTypeDataSize(1, 40)
  }

  /**
   * 区域
   * */
  addRegion(width = LEDSender.Region_width, height = LEDSender.Region_height) {
    this.shortFill(0x3E) //Id	2	章节标识代码 =0x3E
    this.shortFill(0) //No	2	置0
    this.shortFill(0) //Over	2	置0
    this.shortFill(1) //Count	2	页面数量
    this.intFill(32) //Size	4	数据长度，TChapter长度+所有子数据长度
    this.intFill(0) //Rect	Left	4	区域左上角X坐标（置0）
    this.intFill(0) //Rect	Top	4	区域左上角Y坐标（置0）
    this.intFill(width) //Rect	Right	4	区域右下角X坐标（置显示屏宽度）
    this.intFill(height) //Rect	Bottom	4	区域右下角Y坐标（置显示屏高度）
    this.intFill(0) //Reserved	4	置0

    this.changeTypeDataSize(2, 32)
  }

  /**
   * 页面
   * */
  addLeaf() {
    this.shortFill(0x30) //Id	2	章节标识代码 =0x30
    this.shortFill(0) // No	2	置0
    this.shortFill(1) // Wait	2	是否等待播放完成 =1等待 =0到时间就切
    this.shortFill(0) // Serial	2	置0
    this.shortFill(1) // Count	2	对象数量
    this.shortFill(0xFFFF) // Reserved	2	存在时间长度
    this.intFill(0x7FFFFFFF) // Time	4	时间长度（毫秒）
    this.intFill(24) // Size	4	数据长度，TLeaf长度+所有子数据长度
    this.shortFill(0) // Reserved1	2	置0
    this.shortFill(0) // Reserved2	2	置0

    this.changeTypeDataSize(3, 24)
  }

  /**
   * 调用 内码对象 和 内码子字符串对象
   * */
  addText(text, left, top,color) {
    this.addWindows(left, top)
    this.AddChildText(text,color)
  }


  /**
   * 内码对象
   * */
  addWindows(left = 0, top = 0, width = LEDSender.Region_width, height = LEDSender.Region_height) {
    if(top!=0){
      top = 16
    }
    this.shortFill(0x3C) //Id	2	章节标识代码 =0x3C
    this.byteFill(1) //Transparent	1	置1
    this.byteFill(0) //Border	1	置0
    this.intFill(28) //Size	4	数据长度，TWindows长度+所有子数据长度
    this.intFill(left) //Rect	Left	4	区域左上角X坐标（置0）
    this.intFill(top) //Rect	Top	4	区域左上角Y坐标（置0）
    this.intFill(width) //Rect	Right	4	区域右下角X坐标（置显示屏宽度）
    this.intFill(height) //Rect	Bottom	4	区域右下角Y坐标（置显示屏高度）
    this.byteFill(0) //Method	1	置0
    this.byteFill(0) //Speed	1	置0
    this.shortFill(1) //Count	2	子字符串对象数量

    this.changeTypeDataSize(4, 28)
  }


  /**
   * 内码子字符串对象
   * */
  AddChildText(text,color=0xFF00) {
    let totalLength = this.getTextLength(text)
    this.shortFill(0x33) //Id	2	章节标识代码 =0x33
    this.byteFill(1) //inMethod	1	引入方式
    this.byteFill(2) //outMethod	1	引出方式
    this.byteFill(0) //stopMethod	1	停留方式
    this.byteFill(0) //Reserved	1	置0
    this.shortFill(1) //inSpeed	2	引入速度
    
    this.shortFill(1) //outSpeed	2	引出速度
    this.shortFill(1) //StopSpeed	2	停留速度
    this.intFill(0x7FFFFFFF) //stopTime	4	停留时间（毫秒）
    this.intFill(0) //Stopx	4	置0
    this.intFill(32 + totalLength) //Size	4	数据长度，TString长度+所有子数据长度
    this.intFill(color) //Color	4	文字颜色 红=0x00FF 绿=0xFF00 黄=0xFFFF
    this.shortFill(0) //Fontset	2	字符集0=16点阵 1=24点阵
    this.shortFill(0) //Reserved2	2	置0

    let textByteSize = this.getByteText(text)
    this.changeTypeDataSize(5, 32 + textByteSize)
  }
 /**
  * 
  * @param {text}} text 
  * @returns 
  */
 getTextLength(text){
  var str = new String(text);  
  var bytesCount = 0;  
  for (var i = 0 ,n = str.length; i < n; i++) {  
      var c = str.charCodeAt(i);  
      if ((c >= 0x0001 && c <= 0x007e) || (0xff60<=c && c<=0xff9f)) {  
          bytesCount += 1;  
      } else {  
          bytesCount += 2;  
      }  
  } 
  let l = bytesCount % 4
    if (l !== 0) {
      let m = 4 - l
      return bytesCount+m; 
    } 
  return bytesCount;  
 }
  getByteText(text) {
    let startIndex = this.currentIndex
    for (let i of text) {
      if (i.charCodeAt() < 255) {
        this.byteFill(i.charCodeAt())
      } else {
        let temp = TextCodec(i);//texts.charCodeAt(Number(strKey))
        console.log(temp,'temp')
        this.byteFill((temp & 0XFF00) >> 8)
        this.byteFill((temp & 0XFF))
      }
    }
    this.byteFill(0x0)
    let n = (this.currentIndex - startIndex) % 4
    if (n !== 0) {
      let m = 4 - n
      for (let i = 0; i < m; i++) {
        this.byteFill(0x0)
      }
    }
    return this.currentIndex - startIndex
  }

  /**
   * 发送的开始包
   * */
  beginPkg() {
    let begin_buf = new Buffer.alloc(8 + 4)
    begin_buf.writeUInt8(85, 0) //55
    begin_buf.writeUInt16LE(0, 1) //Command	 2 	0：起始包 1：结束包 2：数据包 命令代码
    begin_buf.writeUInt8(0, 3) //srcAddr	1	0	源地址
    begin_buf.writeUInt8(this.dstAddr, 4) //dstAddr	1		目标地址（控制卡地址）
    begin_buf.writeUInt32LE(0, 5) //SerialNo	4	从0开始编号,起始包=0 包序列号
    let buf_string = begin_buf.slice(1, begin_buf.length - 3).toString('hex')
    let crc = CRC.ToModbusCRC16(buf_string)
    begin_buf.writeUInt8('0x' + crc[2] + crc[3], 9) //crc校验
    begin_buf.writeUInt8('0x' + crc[0] + crc[1], 10) //crc校验
    begin_buf.writeUInt8(0xAA, 11) //AA
    return begin_buf
  }

  /**
   * 发送的结束包
   * */
  endPkg(seriaNo) {
    let end_buf = new Buffer.alloc(12)
    end_buf.writeUInt8(85, 0) //55
    end_buf.writeUInt16LE(1, 1) //Command	 2 	0：起始包 1：结束包 2：数据包 命令代码
    end_buf.writeUInt8(0, 3) //srcAddr	1	0	源地址
    end_buf.writeUInt8(this.dstAddr, 4) //dstAddr	1		目标地址（控制卡地址）
    end_buf.writeUInt32LE(seriaNo, 5) //SerialNo	4	从0开始编号,起始包=0 包序列号
    let buf_string = end_buf.slice(1, end_buf.length - 3).toString('hex')
    let crc = CRC.ToModbusCRC16(buf_string)
    end_buf.writeUInt8('0x' + crc[2] + crc[3], 9) //crc校验
    end_buf.writeUInt8('0x' + crc[0] + crc[1], 10) //crc校验
    end_buf.writeUInt8(0xAA, 11) //AA
    return end_buf
  }

  /**
   * 发送的数据包，每个包最大为为512
   * @param seriaNo 第几个包
   * @param index 开始打包的位置
   * @param maxSize 发送数据包的大小
   * */
  dataPkg(seriaNo, index, maxSize) {
    let data_buf = new Buffer.alloc(12 + maxSize)
    data_buf.writeUInt8(85, 0) //55
    data_buf.writeUInt16LE(2, 1) //Command	 2 	0：起始包 1：结束包 2：数据包 命令代码
    data_buf.writeUInt8(0, 3) //srcAddr	1	0	源地址
    data_buf.writeUInt8(this.dstAddr, 4) //dstAddr	1		目标地址（控制卡地址）
    data_buf.writeUInt32LE(seriaNo, 5) //SerialNo	4	从0开始编号,起始包=0 包序列号
    this.dataCopy(data_buf, index, maxSize)
    let buf_string = data_buf.slice(1, data_buf.length - 3).toString('hex')
    let crc = CRC.ToModbusCRC16(buf_string)
    data_buf.writeUInt8('0x' + crc[2] + crc[3], maxSize + 9) //crc校验
    data_buf.writeUInt8('0x' + crc[0] + crc[1], maxSize + 10) //crc校验
    data_buf.writeUInt8(0xAA, maxSize + 11) //AA
    return data_buf
  }

  dataCopy(data_buf, index, maxSize) {
    for (let i = 0; i < maxSize; i++) {
      data_buf.writeUInt8(this.data_stream[i + index], i + 9)
    }
  }

  /**
   * 获取数据包的总长度
   * */
  getPkgSize() {
    return this.currentIndex
  }

  show() {
    return this.data_stream.slice(0, this.currentIndex)
  }

}

let led_sender = new LEDSender()
let udpClient = new MyUdpSocket()
//文字颜色 绿=0x00FF 红=0xFF00 黄=0xFFFF
fn('过磅完成请下磅',0xFFFF , 0, 0)

function fn(text,color,left,top) {
  led_sender.makeRoot()
  led_sender.addChapter()
  led_sender.addRegion()
  led_sender.addLeaf()
  led_sender.addText(text, left, top,color)
  let begin = led_sender.beginPkg()
  let pkg_no = 1 
  // console.log(begin)
  let data = led_sender.dataPkg(1, 0, led_sender.getPkgSize())
  console.log(data.toString('hex').toUpperCase())
  pkg_no += 1
  let end = led_sender.endPkg(2)
  // console.log(end)
  let temp = [end, data, begin]
   udpClient.send(begin)
  setTimeout(( ) => {
    udpClient.send(data)
  },300)

  setTimeout(() => {
    udpClient.send(end)
  },800) 
}